package com.asialjim.wechat.message;

import com.asialjim.wechat.pojo.account.WeChatAccountType;
import com.asialjim.wechat.utils.ClassUtils;
import com.asialjim.wechat.utils.JsonUtils;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlCData;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import net.sf.cglib.beans.BeanCopier;

import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;

/**
 * <h1><em>ASIAL JIM JAVA DOC</em></h1><hr/>
 * <h2>CLASS DESCRIPTION <i>[ NAME: AbstractWeChatCallMessage ]</i></h2><strong>
 * <p> we chat call message body
 * </strong><p><p><em>Copyright &copy; Asial Jim Co., LTD</em><hr/>
 *
 * @author Asial Jim &nbsp;&nbsp; <span>Email:<a href="mailto:asialjim@hotmail.com">asialjim@hotmail.com</a> &nbsp;&nbsp; <a href="asialjim@qq.com">asialjim@qq.com</a></span>
 * @version 1.0.0
 * @since 2021/1/26   &nbsp;&nbsp; JDK 8
 */
@Data
@Slf4j
@JacksonXmlRootElement(localName = "xml")
public class BaseWeChatCallMessage implements WeChatMessage {
    private static final Map<String,BeanCopier> BEAN_COPIER_CACHE = new ConcurrentHashMap<>();
    private static final String BEAN_COPIER_CACHE_KEY_TEMPLATE = "CALL_MESSAGE:BEAN_COPIER:%s:%s";
    private static final String RECEIVE_MESSAGE_LOG = "\r\n\r\n>>>>>>>>>>=========== RECEIVE MESSAGE FROM WE CHAT SERVER ==========<<<<<<<<<<\r\n{}\r\n>>>>>>>>>>=========== RECEIVE MESSAGE FROM WE CHAT SERVER ==========<<<<<<<<<<\r\n";

    @JacksonXmlCData
    @JacksonXmlProperty(localName = "ToUserName")
    protected String toUserName;

    @JacksonXmlCData
    @JacksonXmlProperty(localName = "FromUserName")
    protected String fromUserName;

    @JacksonXmlProperty(localName = "CreateTime")
    protected Long createTime;

    @JacksonXmlCData
    @JacksonXmlProperty(localName = "MsgType")
    protected String msgType;

    @JacksonXmlProperty(localName = "MsgId")
    protected Long msgId;

    @JacksonXmlCData
    @JacksonXmlProperty(localName = "Event")
    protected String event;

    @JacksonXmlCData
    @JacksonXmlProperty(localName = "MediaId")
    protected String mediaId;

    @JacksonXmlProperty(localName = "MenuId")
    protected String menuId;

    @JacksonXmlCData
    @JacksonXmlProperty(localName = "EventKey")
    protected String eventKey;

    @JacksonXmlCData
    @JacksonXmlProperty(localName = "PicUrl")
    protected String picUrl;

    @JacksonXmlCData
    @JacksonXmlProperty(localName = "Title")
    protected String title;

    @JacksonXmlCData
    @JacksonXmlProperty(localName = "Description")
    protected String description;

    @JacksonXmlCData
    @JacksonXmlProperty(localName = "Url")
    protected String url;

    @JacksonXmlProperty(localName = "Latitude")
    protected String latitude;

    @JacksonXmlProperty(localName = "Longitude")
    protected String longitude;

    @JacksonXmlProperty(localName = "Precision")
    protected String precision;

    @JacksonXmlProperty(localName = "Location_X")
    protected String locationX;

    @JacksonXmlProperty(localName = "Location_Y")
    protected String locationY;

    @JacksonXmlProperty(localName = "Scale")
    protected String scale;

    @JacksonXmlCData
    @JacksonXmlProperty(localName = "Label")
    protected String label;

    @JacksonXmlCData
    @JacksonXmlProperty(localName = "Ticket")
    protected String ticket;

    @JacksonXmlCData
    @JacksonXmlProperty(localName = "Content")
    protected String content;

    @JacksonXmlCData
    @JacksonXmlProperty(localName = "ThumbMediaId")
    protected String thumbMediaId;

    @JacksonXmlCData
    @JacksonXmlProperty(localName = "Format")
    protected String format;

    @JacksonXmlCData
    @JacksonXmlProperty(localName = "Recognition")
    protected String recognition;

    @JacksonXmlCData
    @JacksonXmlProperty(localName = "AppId")
    protected String appId;

    @JacksonXmlCData
    @JacksonXmlProperty(localName = "PagePath")
    protected String pagePath;

    @JacksonXmlCData
    @JacksonXmlProperty(localName = "ThumbUrl")
    protected String thumbUrl;

    @JacksonXmlCData
    @JacksonXmlProperty(localName = "SessionFrom")
    protected String sessionFrom;

    @JacksonXmlProperty(localName = "bizmsgmenuid")
    protected String bizMsgMenuId;

    @JacksonXmlCData
    @JacksonXmlProperty(localName = "Encrypt")
    protected String encrypt;

    @JacksonXmlProperty(localName = "ScanCodeInfo")
    protected ScanCodeInfo scanCodeInfo;

    @JacksonXmlProperty(localName = "SendPicsInfo")
    private SendPicsInfo sendPicsInfo;

    @JacksonXmlProperty(localName = "SendLocationInfo")
    private SendLocationInfo sendLocationInfo;

    /**
     * <h1><em>ASIAL JIM JAVA DOC</em></h1><hr/>
     * <h2>CLASS DESCRIPTION <i>[ NAME: BaseWeChatCallMessage ]</i> </h2><strong>
     * <p> scan qr code push event xml request
     * </strong><p><p>Copyright &copy; Asial Jim Co., LTD<hr/>
     * @author Asial Jim &nbsp;&nbsp; <span>Email:<a href="mailto:asialjim@hotmail.com">asialjim@hotmail.com</a> &nbsp;&nbsp; <a href="asialjim@qq.com">asialjim@qq.com</a></span>
     * @since 2021/3/15 14:55   &nbsp;&nbsp; JDK 8
     * @version 1.0.0
     */
    @Data
    public static class ScanCodeInfo{

        @JacksonXmlCData
        @JacksonXmlProperty(localName = "ScanType")
        private String scanType;

        @JacksonXmlCData
        @JacksonXmlProperty(localName = "ScanResult")
        private String scanResult;
    }

    @Data
    public static class SendPicsInfo{

        @JacksonXmlProperty(localName = "Count")
        private Integer count;

        @JacksonXmlProperty(localName = "PicList")
        private PicList picList;
    }

    @Data
    public static class PicList{

        @JacksonXmlProperty(localName = "item")
        private List<PicMd5Sum> item;
    }

    @Data
    public static class PicMd5Sum{

        @JacksonXmlCData
        @JacksonXmlProperty(localName = "PicMd5Sum")
        private String picMd5Sum;
    }

    @Data
    public static class SendLocationInfo{
        @JacksonXmlCData
        @JacksonXmlProperty(localName = "Location_X")
        private String locationX;

        @JacksonXmlCData
        @JacksonXmlProperty(localName = "Location_Y")
        private String locationY;

        @JacksonXmlCData
        @JacksonXmlProperty(localName = "Scale")
        private String scale;

        @JacksonXmlCData
        @JacksonXmlProperty(localName = "Lable")
        private String label;

        @JacksonXmlCData
        @JacksonXmlProperty(localName = "Poiname")
        private String poiname;
    }



    /**
     * <h3>METHOD DESCRIPTION <i>[ NAME: genWeChatMessage ]</i></h3>
     * generate we chat message from this we chat call message
     * @param accountType {@link WeChatAccountType accountType}
     * @return {@link WeChatMessage we chat message}
     * @author Asial Jim &nbsp;&nbsp;<span>Email:asialjim@hotmail.com &nbsp;&nbsp; asialjim@qq.com</span>
     * @since 2021/1/27 9:59
     */
    public WeChatMessage genWeChatMessage(WeChatAccountType accountType){
        log.info(RECEIVE_MESSAGE_LOG, ClassUtils.toNotNullString(this));
        WeChatMessage weChatMessage = null;
        try {
            Class<? extends WeChatMessage> weChatMessageClass = genMessage(accountType);
            weChatMessage = weChatMessageClass.newInstance();
            String beanCopierCacheKey = genBeanCopierCacheKey(this.getClass(), weChatMessage.getClass());
            BeanCopier copier = Optional.ofNullable(BEAN_COPIER_CACHE.get(beanCopierCacheKey)).orElse(BeanCopier.create(this.getClass(),weChatMessage.getClass(),false));
            BEAN_COPIER_CACHE.putIfAbsent(beanCopierCacheKey,copier);
            copier.copy(this,weChatMessage,null);
        } catch (IllegalAccessException | InstantiationException e) {
            log.error("\r\n>>>=========<<<\r\n获取目标消息出现异常,异常信息:\r\n{}\r\n>>>=========<<<",e.getMessage());
        }
        log.debug("\r\n封装消息结果：{}:{}\r\n", this.getClass().getSimpleName(), JsonUtils.toJson(weChatMessage));
        return weChatMessage;
    }

    /**
     * <h3>METHOD DESCRIPTION <i>[ NAME: genBeanCopierCacheKey ]</i></h3>
     * get bean copier cache key by source class and target class
     * @param sourceClass {@link Class sourceClass}
     * @param targetClass {@link Class targetClass}
     * @return {@link String cache key}
     * @author Asial Jim &nbsp;&nbsp;<span>Email:asialjim@hotmail.com &nbsp;&nbsp; asialjim@qq.com</span>
     * @since 2021/1/27 9:58
     */
    private String genBeanCopierCacheKey(Class<?> sourceClass, Class<?> targetClass){
        return String.format(BEAN_COPIER_CACHE_KEY_TEMPLATE,targetClass.getName(),sourceClass.getName());
    }

//    /**
//     * <h3>METHOD DESCRIPTION <i>[ NAME: genMessage ]</i></h3>
//     * generate we chat message class
//     * @param accountType {@link WeChatAccountType accountType}
//     * @return {@link Class<WeChatMessage> we chat message class}
//     * @author Asial Jim &nbsp;&nbsp;<span>Email:asialjim@hotmail.com &nbsp;&nbsp; asialjim@qq.com</span>
//     * @since 2021/1/27 9:55
//     */
//    public abstract Class<? extends WeChatMessage> genMessage(WeChatAccountType accountType);
//
//    /**
//     * <h3>METHOD DESCRIPTION <i>[ NAME: messageType ]</i></h3>
//     * get we chat message type
//     * @param accountType {@link WeChatAccountType accountType}
//     * @return {@link WeChatMessageType we chat message type}
//     * @author Asial Jim &nbsp;&nbsp;<span>Email:asialjim@hotmail.com &nbsp;&nbsp; asialjim@qq.com</span>
//     * @since 2021/1/27 9:56
//     */
//    public abstract String messageTypeName(WeChatAccountType accountType);


    public Class<? extends WeChatMessage> genMessage(WeChatAccountType accountType) {
        return WeChatMessage.class;
    }

    public String messageTypeName(WeChatAccountType accountType) {
        return "DEFAULT";
    }
}